const jwt = require('jsonwebtoken');
const config = require('../config');
const AuthService = require('../services/AuthService');
const User = require('../models/User');
const { UnauthorizedError, ForbiddenError, BadRequestError } = require('../utils/errors');

/**
 * 验证JWT令牌
 * @param {string} token - JWT令牌
 * @returns {Object} 解码后的令牌数据
 * @throws {UnauthorizedError} 令牌无效或过期时抛出错误
 */
function verifyToken(token) {
  try {
    return jwt.verify(token, config.auth.jwt.secret, {
      issuer: config.auth.jwt.issuer,
      audience: config.auth.jwt.audience
    });
  } catch (error) {
    if (error.name === 'TokenExpiredError') {
      throw new UnauthorizedError('认证令牌已过期');
    }
    throw new UnauthorizedError('无效的认证令牌');
  }
}

/**
 * JWT认证中间件
 * @param {Object} req - Express请求对象
 * @param {Object} res - Express响应对象
 * @param {Function} next - 下一个中间件
 */
async function authenticateJWT(req, res, next) {
  try {
    // 获取Authorization头
    const authHeader = req.headers.authorization;
    
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      throw new UnauthorizedError('缺少认证令牌');
    }
    
    // 提取令牌
    const token = authHeader.split(' ')[1];
    
    // 验证令牌
    const decoded = verifyToken(token);
    
    // 获取用户信息 - 使用decoded.id而不是decoded.userId
    const user = await User.findByPk(decoded.id);
    
    if (!user) {
      throw new UnauthorizedError('用户不存在');
    }
    
    // 设置用户信息到请求对象
    req.user = {
      id: user.id,
      username: user.username,
      role: user.role || 'user',
      nickname: user.nickname || user.username
    };
    
    next();
  } catch (error) {
    if (error instanceof UnauthorizedError) {
      return res.status(401).json({
        success: false,
        code: 401,
        message: error.message
      });
    }
    res.status(500).json({
      success: false,
      code: 500,
      message: '认证过程中发生错误'
    });
  }
}

/**
 * 角色验证中间件
 * @param {Array<string>} requiredRoles - 允许的角色列表
 * @returns {Function} 中间件函数
 */
function authorizeRole(...requiredRoles) {
  return (req, res, next) => {
    try {
      // 确保用户已认证
      if (!req.user) {
        throw new UnauthorizedError('需要先认证');
      }
      
      // 检查用户角色
      const userRole = req.user.role;
      if (!userRole) {
        throw new ForbiddenError('用户角色未定义');
      }
      
      // 检查是否有允许的角色
      if (!requiredRoles.includes(userRole)) {
        throw new ForbiddenError('权限不足：需要以下角色之一: ' + requiredRoles.join(', '));
      }
      
      next();
    } catch (error) {
      next(error);
    }
  };
}

/**
 * 权限验证中间件
 * @param {Array<string>} requiredPermissions - 允许的权限列表
 * @returns {Function} 中间件函数
 */
function authorizePermission(...requiredPermissions) {
  return (req, res, next) => {
    try {
      // 确保用户已认证
      if (!req.user) {
        throw new UnauthorizedError('需要先认证');
      }
      
      // 管理员拥有所有权限
      if (req.user.role === config.auth.roles.ADMIN) {
        return next();
      }
      
      const userRole = req.user.role;
      const rolePermissions = config.auth.rolePermissions[userRole] || [];
      
      // 检查用户是否有所需的全部权限
      const hasAllPermissions = requiredPermissions.every(permission => 
        rolePermissions.includes(permission)
      );
      
      if (!hasAllPermissions) {
        throw new ForbiddenError('权限不足：缺少必要的权限');
      }
      
      next();
    } catch (error) {
      next(error);
    }
  };
}

/**
 * 管理员权限中间件
 * @returns {Function} 中间件函数
 */
function authorizeAdmin() {
  return authorizeRole(config.auth.roles.ADMIN);
}

/**
 * 可选认证中间件（不强制要求认证，但如果提供了有效令牌则进行认证）
 * @param {Object} req - Express请求对象
 * @param {Object} res - Express响应对象
 * @param {Function} next - 下一个中间件
 */
async function optionalAuth(req, res, next) {
  try {
    const authHeader = req.headers.authorization;
    
    if (authHeader) {
      const tokenParts = authHeader.split(' ');
      if (tokenParts.length === 2 && tokenParts[0] === 'Bearer') {
        try {
          const token = tokenParts[1];
          const decoded = verifyToken(token);
          
          // 查找用户并验证状态
          const user = await User.findByPk(decoded.id);
          if (user && user.status === 1) {
            req.user = {
              id: user.id,
              username: user.username,
              email: user.email,
              role: user.role
            };
            req.token = {
              decoded,
              raw: token
            };
          }
        } catch (error) {
          // 忽略无效令牌，继续处理请求
          console.warn('无效的可选认证令牌');
        }
      }
    }
    
    next();
  } catch (error) {
    next();
  }
}

/**
 * 验证用户是否为资源所有者中间件
 * @param {string} resourceIdField - 请求中资源ID的字段名
 * @param {Function} getResourceOwnerId - 获取资源所有者ID的函数
 * @returns {Function} Express中间件函数
 */
function requireOwner(resourceIdField, getResourceOwnerId) {
  return async (req, res, next) => {
    try {
      // 确保用户已认证
      if (!req.user) {
        throw new UnauthorizedError('用户未认证');
      }

      // 获取资源ID
      const resourceId = req.params[resourceIdField] || req.body[resourceIdField];
      if (!resourceId) {
        throw new BadRequestError(`缺少资源ID参数: ${resourceIdField}`);
      }

      // 检查是否为管理员（管理员可以访问所有资源）
      if (req.user.role === config.auth.roles.ADMIN) {
        return next();
      }

      // 获取资源所有者ID
      const ownerId = await getResourceOwnerId(resourceId);
      
      // 检查用户是否为资源所有者
      if (ownerId !== req.user.id) {
        throw new ForbiddenError('无权访问此资源');
      }

      next();
    } catch (error) {
      next(error);
    }
  };
}

module.exports = {
  authenticateJWT,
  authorizeRole,
  authorizePermission,
  authorizeAdmin,
  optionalAuth,
  requireOwner,
  verifyToken
};

// 默认导出JWT认证中间件
module.exports.default = authenticateJWT;